home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AOL File Library: 4,101 to 4,200
/
aol-file-protocol-4400-4101-to-4200.zip
/
AOLDLs
/
ADV - Articles & Misc
/
DYA TechNote #03_ SHR Animation
/
TN.DYA.03.V1.1
< prev
Wrap
Text File
|
2014-11-30
|
18KB
|
411 lines
*-----------------------------------------------------------------------------*
DYA TechNote #3: Basic animation theories.
Written by: Jim Maricondo June 10, 1990 Version 1.1
*-----------------------------------------------------------------------------*
Although this technote is not copyrighted in any way, I'd
appreciate it if you asked permission first if you wanted to distribute it in a
non-electronic form. Thanks. Please tell me what you think of it. I'm still
deciding whether to release DYA TechNotes 1 and 2... Oh well, here is the
technote. It's not that professional, because I figured why put all that extra
time into it if hardly anyone's going to see it? If you have any questions,
email me or post them.
Welcome to DYA TechNote number three on basic animation
theories. Because of the GS's lack of speed, programming decent animation is
often a challenge. We all take for granted other people's programs out there
that do all kinds of neat stuff, but then we think, "Now how in the hell would
I do that?" Also, please note that all the stuff talked about in this TechNote
refers to 320 mode. Note that this is only a BASIC discussion; I'm not going
to go into all kinds of detail about the screen in memory. If you want detail,
buy the Hardware Reference. Note also that whenever you are using any memory
that is not normally SHR memory (like bank $01 and your background bank) be
sure to allocate it thru the Memory Manager, and if you can't get it, display
an error message and quietly quit.
THE SHR SCREEN
First let's talk about the SuperHiRes (SHR) screen in memory.
The pixel data itself starts at $E12000, and runs to $E19D00. Each pixel on
the screen is one nibble (1/2 byte) in memory. Thus a scanline of 320 pixels
takes up 160 ($A0) bytes in memory. ($A0 x 200 = $7D00.) Next after the pixel
data are the ScanLine Control Bytes, or SCB's. There is one of these for every
scan line. They technically run from $E19D00 thru $E19D67. The SCB for line
one is at $E19D00, the SCB for line two is at $E19D01, etc. SCB's tell whether
the line is 320 pixels wide or 640 pixels wide, whether the line will generate
interrupts, whether color fill mode is enabled on that line, and which palette
that line will use. Palette data runs from $E19E00 to $E19FFF. Each color in
a palette is two bytes, and there are 16 colors in a palette, and 16 palettes.
All palette data is stored in memory sequentially.
BEGINNING ANIMATION AND SPEEDING THINGS UP SOME
The obvious method of animation is just to load and store values
to the screen in bank $E1. However, once you start to do anything major, this
becomes too slow and awkward for much. All values written and read from bank
$E1 are written and read at 1 mHZ! It's bad enough the GS is slow, but who
wants to do speed eating animation at the speed of a IIe? This is where
shadowing comes in. By flipping the correct softswitch, whatever written in
bank $01 is automatically also written to bank $E1 at fast 2.8 mHZ! This is
the first step in efficient animation.
PRESERVING THE BACKGROUND AND AVOIDING FLICKER
So we're happily doing all our drawing to bank $01 now, but how
can we animate shapes over a background that isn't just a solid color? Use
another bank just for the background. I would recommend use of banks $06, $07,
$08, or $09 because these banks aren't used that often by the system. In this
example, I'll use bank $09. After allocating $092000 to $09A000 successfully
thru the memory manager, we will procede to load our background picture into
$092000. We then allocate $012000 to $01A000 thru the memory manager, and upon
no error we continue. Now, the basic theory behind preserving the background
is this:
1) Copy the background from the background bank ($09 here) to bank $01.
2) Draw your shapes over the background in bank $01.
3) Repeat.
However, this is also very slow as we are doing a lot of stuff we don't really
need to do. We can help to optimize this method by only ONLY copying the
background in bank $09 over the area where the shape OCCUPIED in bank $01, not
copying the whole background over all of bank $01.
Still, this method is flawed. Often, your shapes will flicker
beyond belief. Let's present a new method around this:
1) Copy the whole background to bank $01.
2) Turn off shadowing.
3) Draw shapes in bank $01, thus drawing them over the background copied to
bank $01.
4) Turn on shadowing, and copy everything onto itself in bank $01, thus quickly
transferring it to bank $E1 and onto the screen.
5) Turn off shadowing.
6) Copy background from bank $09 over only the area where the shape was.
7) Repeat steps 3 thru 6.
This way you never see the shape being erased and then drawn
again, you only see a nice new frame of animation where the shape is somewhere
different. There is NO flicker!
SCREEN UPDATE TECHNIQUES - MVN
While there is no flicker, this method can be slow. One way to
speed it up is to use an efficient method of copying everything onto itself.
The easiest method to understand, but which is very slow, is to use MVN. Here
is an example of copying everything onto itself using MVN.
MVNUpdate anop
shortm
lda $E0C035 turn on SHR shadowing
and #$F7
sta $E0C035
longm
ldx #$2000 start at $2000
txy
lda #$7E00-1 screen data is $7E00 bytes
mvn $012000,$E12000 use shadowing to quickly copy each byte
onto itself
phk always reset data bank after mvn
plb
shortm
lda $E0C035 turn off SHR shadowing
ora #$08
sta $E0C035
longm
For the technical types, this method does it at 7 cycles a byte.
There is a method twice as fast using the stack. But in order to understand
it, we must understand the stack, and how it can be used in animation. A quick
look at the 65816's instruction set shows you that the operations that take the
least time to complete involve the stack. There is another softswitch we can
flip that will let us have the stack in bank $01 instead of in bank $00. So we
can align the stack pointer to the SHR screen, and by pushing values onto the
stack, we'd be "pushing" pixels onto the screen. When the stack is here, we
don't need to PULL off everything we pushed onto it as we do in normal
programming.
SCREEN UPDATE TECHNIQUES - PEI
Next, let's take the PEI instruction. PEI stands for Push
Effective Indirect. PEI ($xx) and PEI $xx mean the same. PEI $xx is the
equivalent of "lda $xx, pha". PEI takes the direct page location specified by
the operand and pushes it. Now if we align the stack and the direct page in
the correct way, a list of PEI's can actually update the screen for us! I know
this may seem a little far fetched as of now. I know it will probably take
time to sink in. First, let me present the stack based equivalent of the MVN
method above. Then I'll explain in more detail.
StackUpdate anop
php ; save whether interrupts were enabled at first
sei disable interrupts
phd save old direct page register
tsc save off old stack pointer
sta StackTemp
shortm
lda $E0C035 turn on SHR shadowing
and #$F7
sta $E0C035
lda $E0C068 turn on bank $01 direct page & stack
ora #$30
sta $E0C068
longm
lda #$9D00
tcs
lda #$9D00-$FF
tcd
ldy #125 repeat loop 125 times --> 125 = $7D,
and since we update $100 bytes per one
execution of this loop, $7D x $100 =
$7D00, or all of the SHR pixel data
sec
loop anop
pei $FE
pei $FC
pei $FA
... all the inbetween pei's...
pei $04
pei $02
pei $00
tdc
sbc #$FF subtract $FF from the direct page reg.
tcd (see explaination below!)
dey done 125 repetitions yet?
jne loop if not, loop again
shortm
lda $E0C035 turn off SHR shadowing
ora #$08
sta $E0C035
lda $E0C068 turn off bank $01 dp/stack
and #$CF
sta $E0C068
longm
lda StackTemp restore original stack pointer
tcs
pld restore original direct page pointer
plp restore original interrupt status
... (your code here)
StackTemp ds 2
We have to disable interrupts, because if a routine interrupts
in the middle of the update, and the routine uses the stack (ALL interrupts do
no matter what, unless you rewrite the system interrupt manager, but that's
another thing) and since whatever pushed onto the stack goes to the SHR screen,
you will get parts of the screen messed up.
It is best to try to have the direct page register have a lo
byte of 00. Because when the low byte is zero, each PEI instruction is one
cycle faster. One cycle might not seem like a lot, but oodles of PEI
instructions would add up! The above example does not do this, as I am not in
the mood to rewrite it to keep the lo bite of the direct page register zero.
The above stack based update routine is only meant as an
example. I would not recommend updating the WHOLE screen for each frame, as
even using the stack for updates, the WHOLE screen can only be updated at about
two to three frames a second (fps). It is best to only update the part of the
screen that needs updating using the stack. I will leave writing a modified
version of the above routine that only updates the area where you want it to
you, and I will also leave implementing code to make sure the lo byte of the
direct page register is zero also to you.
We align the direct page pointer always $FF bytes ahead in
memory BEFORE the stack. Let me try to explain this. Say the direct page
register is set to $9D00 and the stack is set to $9DFF. When we PEI $FE, it is
really saying "load $9DFE {the value of the operand added to the value of the
direct page register} and push it to $9DFE {the stack pointer is decremented,
and then the value at that direct page location is stored to the value
of the new stack pointer, $9DFE}." This is also why at the end of the update,
we only need to subtract $FF from the direct page, and NOT the stack; because
the stack is automatically decremented, and the direct page is not.
I have not actually tested the above code, as I don't update the
entire screen for one frame, but theoretically it should work fine. Also, all
data in your original program's direct page will be perfectly preserved!
USING THE STACK FOR SCROLLING
This gets even more confusing than just updating the screen! I
strongly suggest that if this is all new to you, don't bother with this section
until you really understand stack based updates!
By carefully manipulating the stack and direct page, you can use
the stack to do ULTRA FAST scrolling, as in the intro screen to my Photon
program. This method has its pro's and con's. While it CAN be VERY fast, it
can really fry your brain out! It is a big pain in the a$$ to understand, and
even harder to program in the first place! Also, you CAN mess up and make it
SLOW. It would still be faster than normal methods, but slower than how fast
it COULD be. In addition to making sure the lo byte of the DP register is
always zero, you need to speed it up by only making it move the area of the
screen that needs scrolling, not just the entire screen. This is really hard.
I spent 4 hours frying my brain out on the stack scroll routine that my Photon
program uses. You need to know a great deal about the GS's hardware, and about
programming in assembly. Also, some scrollings are not possible using the
stack. It has a very limited use. For instance, you can't scroll stuff from
right to left using PEI, (you have to use pla, sta $xx instead), and you can't
scroll up one line and keep the lo byte of the DP register zero. Read with
caution!
Next I will present what I feel is the easiest stack based
scroll to understand. It scrolls the ENTIRE screen down one line. To the
non-programmer it looks slow. But to the programmer, it is a massive speed up
over doing (lda $012000,x inx ... sta $012000,x ... ). It keeps the lo byte of
the DP register zero tho. I will leave you to figure out how to repeat it
several times. Just remember once you change the stack to bank 01, you can't
use the stack for anything EXCEPT graphics. That means NO jsr's, jsl's, pha's,
phx's, per's, phy's, etc. ONLY PEI's and if you are pushing PEA $xxxx onto the
screen! Most importantly you must NOT make any toolbox or GS/OS calls while
the stack and direct page are in bank 01!!!
MoveDown1Line anop
php ; save whether interrupts were enabled at first
sei disable interrupts
phd save old direct page register
tsc save off old stack pointer
sta StackTemp
shortm
lda $E0C035 turn on SHR shadowing
and #$F7
sta $E0C035
lda $E0C068 turn on bank $01 direct page & stack
ora #$30
sta $E0C068
longm
lda #$9CFF
tcs
lda #$9C00
tcd
brl Start5E
loop anop
pei $FE
pei $FC
pei $FA
... all the inbetween pei's...
pei $60
Start5E pei $5E
pei $5C
...
pei $04
pei $02
pei $00
sec
sbc #$100 subtract $100 from the DP register
! we don't have to do tdc before this cuz the accm already has the DP reg in it
cmp #$2000 done the whole screen yet?
blt Yes
tcd
brl loop
Yes anop
shortm
lda $E0C035 turn off SHR shadowing
ora #$08
sta $E0C035
lda $E0C068 turn off bank $01 dp/stack
and #$CF
sta $E0C068
longm
lda StackTemp restore original stack pointer
tcs
pld restore original direct page pointer
plp restore original interrupt status
... (your code here)
StackTemp ds 2
Here is an explanation I wrote earlier in the Photon code
segment source code. I am sorry that it uses $5100 and $51FF as an example
instead of $9C00 and $9CFF that are used in the above source, but I don't feel
like re-frying my brain out to rewrite it. I just am not to interested in
having my head explode. :)
* For instance, if I set the direct page to $5100 and the stack to $51FF,
* and then do a PEI $5E, what is happening is:
* the value at the direct page register + $5E, in this case it's
* $515E,is stored (pushed)to the address of the stack decremented, or
* in this case $51FE. Now, graphics line $4F starts at $5160, and
* line $50 starts at $5200. What is actually happening is the last
* four pixels (one word) of line $4F are being stored in exactly the
* same physical location one line down, all at an incredible speed
* improvement over loading and storing to bank E1 using absolute
* indexed with X or absolute long indexed with X addressing. Note
* that 5E and FE are exactly A0 (160) bytes apart; the length of one
* line of graphics in memory.
* Then I PEI additional values until we have done a PEI $00. Then I
* subtract $100 from the direct page (I don't need to subtract anything
* from the stack as it is automatically incremented/decremented) and
* repeat starting at PEI $FE (since we've already established our A0 byte
* (1 line) variance, I don't need to start at PEI $5E again) until I
* detect that we've moved the entire shape exactly one line down, by
* checking if the direct page register is less than the end of the SHR pixel dat
* pixel data.
That's about it for Version 1.1 of DYA TechNote #3. In the
future, I might write an Advanced Animation Techniques TechNote, when I learn
more advanced techniques. If you like this, please tell me, as if noone says
anything, I probably won't write (or won't release) other possible TechNotes.
Jim Maricondo June 10, 1990
CONTACTS:
America Online: `DYA Jim`
GEnie: `J.Maricondo1`
___________________
Further References: (let's face it there isn't a lot of stuff on animation!)
o Call Apple Winter 1989/1990, pages 8 thru 23.
o Apple IIgs Hardware Reference, pages 55 thru 99.
o Apple IIgs TechNote #70.